/*
 * invulgotracker
 * Copyright (C) Thomas Andersen 2011 <thomas.1.andersen@gmail.com>
 * 
 * invulgotracker is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * invulgotracker is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>
#include "report.h"
#include <glade/glade.h>
#include "config.h"
#include "gettextmacro.h"

#include "invulgotrackerapp.h"


extern GladeXML *gxml;

Report *Report::singleton = NULL;

extern "C" gboolean on_windowReport_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
    delete Report::GetReport();
    return TRUE;
}


extern "C" void on_buttonReportShow_clicked(GtkButton *button, gpointer user_data)
{
    Report::GetReport()->Generate();
}


extern "C" void on_buttonReportDetail_clicked(GtkButton *button, gpointer user_data)
{
    Report::GetReport()->GenerateDetails();
}


extern "C" void on_buttonReportTasks_clicked(GtkButton *button, gpointer user_data)
{
    Report::GetReport()->GenerateTasks();
}

extern "C" void on_buttonReportBalance_clicked(GtkButton *button, gpointer user_data)
{
    Report::GetReport()->GenerateBalance();
}

extern "C" void on_buttonReportPrint_clicked(GtkButton *button, gpointer user_data)
{
    Report::GetReport()->Print();
}

extern "C" void on_buttonReportClose_clicked(GtkButton *button, gpointer user_data)
{
    delete Report::GetReport();
}

Report *Report::GetReport()
{
    if (singleton)
        return singleton;
    return singleton = new Report();
}

Report::Report()
{
    window = NULL;
    summaryView = NULL;
    detailView = NULL;
    taskProgressView = NULL;
    balanceView = NULL;
}

void Report::Show()
{
    /* Get window. */
    window = glade_xml_get_widget (InvulgoTrackerApp::gxml, "windowReport");

    gtk_widget_show(window);
	
}


Report::~Report()
{
    gtk_widget_hide(window);
    singleton = NULL;
    if (summaryView)
        delete summaryView;
    if (detailView)
        delete detailView;
    if (taskProgressView)
        delete taskProgressView;
    if (balanceView)
        delete balanceView;
}




void Report::Generate()
{
    guint yearFrom, monthFrom, dayFrom;
    guint yearTo, monthTo, dayTo;
    GtkCalendar *calendar = (GtkCalendar*)glade_xml_get_widget (InvulgoTrackerApp::gxml, "calendarReportFrom");
    gtk_calendar_get_date(calendar, &yearFrom, &monthFrom, &dayFrom);
    TaskTime tt(yearFrom, monthFrom+1, dayFrom);
    calendar = (GtkCalendar*)glade_xml_get_widget (InvulgoTrackerApp::gxml, "calendarReportTo");
    gtk_calendar_get_date(calendar, &yearTo, &monthTo, &dayTo);
    if (summaryView)
        delete summaryView;
    if (detailView)
        delete detailView;
    detailView = NULL;
    if (balanceView)
        delete balanceView;
    balanceView = NULL;
    if (taskProgressView)
        delete taskProgressView;
    taskProgressView = NULL;
    summaryView = new SummaryView();
    GtkWidget *view = glade_xml_get_widget (InvulgoTrackerApp::gxml, "treeviewReport");
    summaryView->Init(view, true);

    summaryView->CalcDay(tt.GetYear(), tt.GetMonth(), tt.GetDay(), TRUE);
    tt = tt.AddDay(1);
    while(((long)yearTo*10000)+((long)(monthTo+1)*100)+(long)dayTo >= ((long)tt.GetYear()*10000)+((long)(tt.GetMonth()+1)*100)+(long)tt.GetDay()) {
        summaryView->CalcDay(tt.GetYear(), tt.GetMonth(), tt.GetDay(), TRUE);
        tt = tt.AddDay(1);
    }

}

void Report::GenerateDetails()
{
    guint yearFrom, monthFrom, dayFrom;
    guint yearTo, monthTo, dayTo;
    GtkCalendar *calendar = (GtkCalendar*)glade_xml_get_widget (InvulgoTrackerApp::gxml, "calendarReportFrom");
    gtk_calendar_get_date(calendar, &yearFrom, &monthFrom, &dayFrom);
    TaskTime tt(yearFrom, monthFrom+1, dayFrom);
    calendar = (GtkCalendar*)glade_xml_get_widget (InvulgoTrackerApp::gxml, "calendarReportTo");
    gtk_calendar_get_date(calendar, &yearTo, &monthTo, &dayTo);
    if (summaryView)
        delete summaryView;
    summaryView = NULL;
    if (taskProgressView)
        delete taskProgressView;
    taskProgressView = NULL;
    if (balanceView)
        delete balanceView;
    balanceView = NULL;
    if (detailView)
        delete detailView;

    detailView = new DetailView();
    GtkWidget *view = glade_xml_get_widget (InvulgoTrackerApp::gxml, "treeviewReport");
    detailView->Init(view, false);

    detailView->CalcDay(tt.GetYear(), tt.GetMonth(), tt.GetDay(), TRUE);
    tt = tt.AddDay(1);
    while(((long)yearTo*10000)+((long)(monthTo+1)*100)+(long)dayTo >= ((long)tt.GetYear()*10000)+((long)(tt.GetMonth()+1)*100)+(long)tt.GetDay()) {
        detailView->CalcDay(tt.GetYear(), tt.GetMonth(), tt.GetDay(), TRUE);
        tt = tt.AddDay(1);
    }

}

void Report::GenerateTasks()
{
    if (summaryView)
        delete summaryView;
    summaryView = NULL;
    if (detailView)
        delete detailView;
    detailView = NULL;
    if (balanceView)
        delete balanceView;
    balanceView = NULL;
    if (taskProgressView)
        delete taskProgressView;
    taskProgressView = new TaskProgressView();
    GtkWidget *view = glade_xml_get_widget (InvulgoTrackerApp::gxml, "treeviewReport");
    taskProgressView->Init(view);
    taskProgressView->Calc();
}

void Report::GenerateBalance()
{
    guint yearFrom, monthFrom, dayFrom;
    guint yearTo, monthTo, dayTo;
    GtkCalendar *calendar = (GtkCalendar*)glade_xml_get_widget (InvulgoTrackerApp::gxml, "calendarReportFrom");
    gtk_calendar_get_date(calendar, &yearFrom, &monthFrom, &dayFrom);
    TaskTime tt(yearFrom, monthFrom+1, dayFrom);
    calendar = (GtkCalendar*)glade_xml_get_widget (InvulgoTrackerApp::gxml, "calendarReportTo");
    gtk_calendar_get_date(calendar, &yearTo, &monthTo, &dayTo);
    if (summaryView)
        delete summaryView;
    summaryView = NULL;
    if (detailView)
        delete detailView;
    detailView = NULL;
    if (taskProgressView)
        delete taskProgressView;
    taskProgressView = NULL;
    if (balanceView)
        delete balanceView;
    balanceView = NULL;
    balanceView = new BalanceView();
    GtkWidget *view = glade_xml_get_widget (InvulgoTrackerApp::gxml, "treeviewReport");
    balanceView->Init(view, true);

    balanceView->CalcDay(tt.GetYear(), tt.GetMonth(), tt.GetDay());
    tt = tt.AddDay(1);
    while(((long)yearTo*10000)+((long)(monthTo+1)*100)+(long)dayTo >= ((long)tt.GetYear()*10000)+((long)(tt.GetMonth()+1)*100)+(long)tt.GetDay()) {
        balanceView->CalcDay(tt.GetYear(), tt.GetMonth(), tt.GetDay());
        tt = tt.AddDay(1);
    }
}

#define HEADER_HEIGHT 50

void Report::PrintPage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble width, textHeight, textWidth;
    gint layoutHeight, layoutWidth;
    //PangoFontDescription *desc;
    gdouble x,y;
    glong skipLines = linesPerPage*page_nr;
    glong lines = 0;

    cr = gtk_print_context_get_cairo_context (context);
    width = gtk_print_context_get_width (context);

//    cairo_rectangle (cr, 0, 0, width, HEADER_HEIGHT);
//    cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
//    cairo_fill (cr);

    layout = gtk_print_context_create_pango_layout (context);
    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
    //desc = pango_font_description_from_string ("sans 14");
    //pango_layout_set_font_description (layout, desc);
    //pango_font_description_free (desc);

    /* Calc new maxWidth if too big. */
    gdouble diff = (maxWidth + 2 + maxWidthTime) - width;
    if (diff > 0)
        maxWidth -= diff;

    /* Print names. */
    gchar *name,*timeStr;
    y = 0;
    if (summaryView->GetFirst(&name,&timeStr)) {
        do {
            if (!skipLines) {
                ++lines;
                x = 0;
                pango_layout_set_text (layout, name, -1);
                pango_layout_set_width(layout, maxWidth*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_MIDDLE);
                pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
                textHeight = (gdouble)layoutHeight / PANGO_SCALE;
                textWidth = (gdouble)layoutWidth / PANGO_SCALE;
                cairo_move_to (cr, x, y);
                x = maxWidth + 2;
                pango_cairo_show_layout (cr, layout);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);

                pango_layout_set_text (layout, timeStr, -1);
                pango_layout_set_width(layout, maxWidthTime*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
                cairo_move_to (cr, x, y);
                pango_cairo_show_layout (cr, layout);
                y += textHeight;
            } else
                --skipLines;
            g_free(name);
            g_free(timeStr);
        } while(lines < linesPerPage && summaryView->GetNext(&name,&timeStr));
    }
    g_object_unref (layout);
}

void Report::PrintBegin(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble height, textHeight = 0, textWidth;
    gint layoutHeight, layoutWidth;
    glong totalCount = 0;

    cr = gtk_print_context_get_cairo_context (context);
    height = gtk_print_context_get_height(context);

    layout = gtk_print_context_create_pango_layout (context);

    /* Calc lines. */
    gchar *name,*timeStr;
    if (summaryView->GetFirst(&name,&timeStr)) {
        do {
            ++totalCount;
            pango_layout_set_text (layout, name, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidth)
                maxWidth = textWidth;
            pango_layout_set_text (layout, timeStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthTime)
                maxWidthTime = textWidth;
            g_free(name);
            g_free(timeStr);
        } while(summaryView->GetNext(&name,&timeStr));
    }

    if (textHeight) {
        linesPerPage = (glong)(height / textHeight);
        gint pages = (gint)(totalCount / (linesPerPage?linesPerPage:totalCount));
        if (pages * linesPerPage < totalCount)
            ++pages;
        if (pages <= 0)
            pages = 1;
        gtk_print_operation_set_n_pages(operation, pages);
    } else
        gtk_print_operation_set_n_pages(operation, 1);

    g_object_unref (layout);
}

extern "C" void Report::DrawPage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    Report::GetReport()->PrintPage(operation, context, page_nr, user_data);
}

extern "C" void Report::BeginPage(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    Report::GetReport()->PrintBegin(operation, context, user_data);
}


void Report::PrintDetailPage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble width, textHeight, textWidth;
    gint layoutHeight, layoutWidth;
    //PangoFontDescription *desc;
    gdouble x,y;
    glong skipLines = linesPerPage*page_nr;
    glong lines = 0;

    cr = gtk_print_context_get_cairo_context (context);
    width = gtk_print_context_get_width (context);

//    cairo_rectangle (cr, 0, 0, width, HEADER_HEIGHT);
//    cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
//    cairo_fill (cr);

    layout = gtk_print_context_create_pango_layout (context);
    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
    //desc = pango_font_description_from_string ("sans 14");
    //pango_layout_set_font_description (layout, desc);
    //pango_font_description_free (desc);

    /* Calc new maxWidth if too big. */
    gdouble diff = (maxWidth + 2 + maxWidthDate + 2 + maxWidthTime) - width;
    if (diff > 0)
        maxWidth -= diff;

    /* Print lines. */
    gchar *dateStr,*name,*timeStr,*prevStr = NULL;
    y = 0;
    if (detailView->GetFirst(&dateStr, &name,&timeStr)) {
        do {
            if (!skipLines) {
                ++lines;
                if (prevStr && strncmp(prevStr,dateStr,10)) {
                    cairo_rectangle(cr, 0, y, width, 1);
                    ++y;
                    cairo_fill(cr);
                }
                if (prevStr)
                    free(prevStr);
                prevStr = strdup(dateStr);
                /* Show date. */
                x = 0;
                pango_layout_set_text (layout, dateStr, -1);
                pango_layout_set_width(layout, maxWidthDate*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
                cairo_move_to (cr, x, y);
                pango_cairo_show_layout (cr, layout);

                /* Show name. */
                x = maxWidthDate + 2;
                pango_layout_set_text (layout, name, -1);
                pango_layout_set_width(layout, maxWidth*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_MIDDLE);
                pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
                textHeight = (gdouble)layoutHeight / PANGO_SCALE;
                textWidth = (gdouble)layoutWidth / PANGO_SCALE;

                cairo_move_to (cr, x, y);
                pango_cairo_show_layout (cr, layout);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);

                /* Show duration.*/
                if (timeStr) {
                    x = maxWidth + 2 + maxWidthDate + 2;
                    pango_layout_set_text (layout, timeStr, -1);
                    pango_layout_set_width(layout, maxWidthTime*PANGO_SCALE);
                    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
                    cairo_move_to (cr, x, y);
                    pango_cairo_show_layout (cr, layout);
                }
                y += textHeight;
            } else
                --skipLines;
            g_free(dateStr);
            g_free(name);
            g_free(timeStr);
        } while(lines < linesPerPage && detailView->GetNext(&dateStr, &name,&timeStr));
        if (prevStr)
            free(prevStr);
    }
    g_object_unref (layout);
}

void Report::PrintDetailBegin(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble height, textHeight = 0, textWidth;
    gint layoutHeight, layoutWidth;
    glong totalCount = 0;

    cr = gtk_print_context_get_cairo_context (context);
    height = gtk_print_context_get_height(context);

    layout = gtk_print_context_create_pango_layout (context);

    /* Calc lines. */
    gchar *dateStr,*name,*timeStr;
    if (detailView->GetFirst(&dateStr, &name,&timeStr)) {
        do {
            ++totalCount;
            pango_layout_set_text (layout, name, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidth)
                maxWidth = textWidth;
            pango_layout_set_text (layout, dateStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthDate)
                maxWidthDate = textWidth;
            pango_layout_set_text (layout, timeStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthTime)
                maxWidthTime = textWidth;
            g_free(dateStr);
            g_free(name);
            g_free(timeStr);
        } while(detailView->GetNext(&dateStr, &name,&timeStr));
    }

    height -= 20; // Make room for 20 divider lines.
    if (textHeight) {
        linesPerPage = (glong)(height / textHeight);
        gint pages = (gint)(totalCount / (linesPerPage?linesPerPage:totalCount));
        if (pages * linesPerPage < totalCount)
            ++pages;
        if (pages <= 0)
            pages = 1;
        gtk_print_operation_set_n_pages(operation, pages);
    } else
        gtk_print_operation_set_n_pages(operation, 1);

    g_object_unref (layout);
}

extern "C" void Report::DrawDetailPage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    Report::GetReport()->PrintDetailPage(operation, context, page_nr, user_data);
}

extern "C" void Report::BeginDetailPage(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    Report::GetReport()->PrintDetailBegin(operation, context, user_data);
}

void Report::PrintTaskPage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble width, textHeight;
    gint layoutHeight, layoutWidth;
    //PangoFontDescription *desc;
    gdouble x,y;
    glong skipLines = linesPerPage*page_nr;
    glong lines = 0;

    cr = gtk_print_context_get_cairo_context (context);
    width = gtk_print_context_get_width (context);

//    cairo_rectangle (cr, 0, 0, width, HEADER_HEIGHT);
//    cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
//    cairo_fill (cr);

    layout = gtk_print_context_create_pango_layout (context);
    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
    //desc = pango_font_description_from_string ("sans 14");
    //pango_layout_set_font_description (layout, desc);
    //pango_font_description_free (desc);

    /* Calc new maxWidth if too big. */
    gdouble diff = (maxWidth + 2 + maxWidthTime + 2 + maxWidthUsed + 2 + maxWidthPct) - width;
    if (diff > 0)
        maxWidth -= diff;

    /* Print lines. */
    gchar *name,*timeStr, *usedStr, *pctStr;
    y = 0;
    if (taskProgressView->GetFirst(&name,&timeStr, &usedStr, &pctStr)) {
        do {
            if (!skipLines) {
                ++lines;
                /* Show name. */
                x = 0;
                pango_layout_set_text (layout, name, -1);
                pango_layout_set_width(layout, maxWidth*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_MIDDLE);
                pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
                textHeight = (gdouble)layoutHeight / PANGO_SCALE;
                cairo_move_to (cr, x, y);
                pango_cairo_show_layout (cr, layout);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);

                /* Show duration.*/
                if (timeStr) {
                    x = maxWidth + 2;
                    pango_layout_set_text (layout, timeStr, -1);
                    pango_layout_set_width(layout, maxWidthTime*PANGO_SCALE);
                    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
                    cairo_move_to (cr, x, y);
                    pango_cairo_show_layout (cr, layout);
                }
                /* Show used.*/
                if (usedStr) {
                    x = maxWidth + 2 + maxWidthTime + 2;
                    pango_layout_set_text (layout, usedStr, -1);
                    pango_layout_set_width(layout, maxWidthUsed*PANGO_SCALE);
                    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
                    cairo_move_to (cr, x, y);
                    pango_cairo_show_layout (cr, layout);
                }
                /* Show pct.*/
                if (pctStr) {
                    x = maxWidth + 2 + maxWidthTime + 2 + maxWidthUsed + 2;
                    pango_layout_set_text (layout, pctStr, -1);
                    pango_layout_set_width(layout, maxWidthPct*PANGO_SCALE);
                    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
                    cairo_move_to (cr, x, y);
                    pango_cairo_show_layout (cr, layout);
                }
                y += textHeight;
            } else
                --skipLines;
            g_free(name);
            g_free(timeStr);
            g_free(usedStr);
            g_free(pctStr);
        } while(lines < linesPerPage && taskProgressView->GetNext(&name,&timeStr, &usedStr, &pctStr));
    }
    g_object_unref (layout);
}

void Report::PrintTaskBegin(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble height, textHeight = 0, textWidth;
    gint layoutHeight, layoutWidth;
    glong totalCount = 0;

    cr = gtk_print_context_get_cairo_context (context);
    height = gtk_print_context_get_height(context);

    layout = gtk_print_context_create_pango_layout (context);

    /* Calc lines. */
    gchar *name,*timeStr, *usedStr, *pctStr;
    if (taskProgressView->GetFirst(&name,&timeStr, &usedStr, &pctStr)) {
        do {
            ++totalCount;
            pango_layout_set_text (layout, name, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidth)
                maxWidth = textWidth;
            pango_layout_set_text (layout, timeStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthTime)
                maxWidthTime = textWidth;

            pango_layout_set_text (layout, usedStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthUsed)
                maxWidthUsed = textWidth;

            pango_layout_set_text (layout, pctStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthPct)
                maxWidthPct = textWidth;
            g_free(name);
            g_free(timeStr);
            g_free(usedStr);
            g_free(pctStr);
        } while(taskProgressView->GetNext(&name,&timeStr, &usedStr, &pctStr));
    }

    if (textHeight) {
        linesPerPage = (glong)(height / textHeight) - 1;
        gint pages = (gint)(totalCount / (linesPerPage?linesPerPage:totalCount));
        if (pages * linesPerPage < totalCount)
            ++pages;
        if (pages <= 0)
            pages = 1;
        gtk_print_operation_set_n_pages(operation, pages);
    } else
        gtk_print_operation_set_n_pages(operation, 1);

    g_object_unref (layout);
}

extern "C" void Report::DrawTaskPage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    Report::GetReport()->PrintTaskPage(operation, context, page_nr, user_data);
}

extern "C" void Report::BeginTaskPage(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    Report::GetReport()->PrintTaskBegin(operation, context, user_data);
}


void Report::PrintBalancePage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble width, textHeight, textWidth;
    gint layoutHeight, layoutWidth;
    //PangoFontDescription *desc;
    gdouble x,y;
    glong skipLines = linesPerPage*page_nr;
    glong lines = 0;

    cr = gtk_print_context_get_cairo_context (context);
    width = gtk_print_context_get_width (context);

//    cairo_rectangle (cr, 0, 0, width, HEADER_HEIGHT);
//    cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
//    cairo_fill (cr);

    layout = gtk_print_context_create_pango_layout (context);
    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
    //desc = pango_font_description_from_string ("sans 14");
    //pango_layout_set_font_description (layout, desc);
    //pango_font_description_free (desc);

    /* Calc new maxWidth if too big. */
    gdouble diff = (maxWidth + 2 + maxWidthTime) - width;
    if (diff > 0)
        maxWidth -= diff;

    /* Print names. */
    gchar *name,*timeStr;
    y = 0;
    if (balanceView->GetFirst(&name,&timeStr)) {
        do {
            if (!skipLines) {
                ++lines;
                x = 0;
                pango_layout_set_text (layout, name, -1);
                pango_layout_set_width(layout, maxWidth*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_MIDDLE);
                pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
                textHeight = (gdouble)layoutHeight / PANGO_SCALE;
                textWidth = (gdouble)layoutWidth / PANGO_SCALE;
                cairo_move_to (cr, x, y);
                x = maxWidth + 2;
                pango_cairo_show_layout (cr, layout);
                pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);

                pango_layout_set_text (layout, timeStr, -1);
                pango_layout_set_width(layout, maxWidthTime*PANGO_SCALE);
                pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
                cairo_move_to (cr, x, y);
                pango_cairo_show_layout (cr, layout);
                y += textHeight;
            } else
                --skipLines;
            g_free(name);
            g_free(timeStr);
        } while(lines < linesPerPage && balanceView->GetNext(&name,&timeStr));
    }
    g_object_unref (layout);
}

void Report::PrintBalanceBegin(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    cairo_t *cr;
    PangoLayout *layout;
    gdouble height, textHeight = 0, textWidth;
    gint layoutHeight, layoutWidth;
    glong totalCount = 0;

    cr = gtk_print_context_get_cairo_context (context);
    height = gtk_print_context_get_height(context);

    layout = gtk_print_context_create_pango_layout (context);

    /* Calc lines. */
    gchar *name,*timeStr;
    if (balanceView->GetFirst(&name,&timeStr)) {
        do {
            ++totalCount;
            pango_layout_set_text (layout, name, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidth)
                maxWidth = textWidth;
            pango_layout_set_text (layout, timeStr, -1);
            pango_layout_get_size (layout, &layoutWidth, &layoutHeight);
            textHeight = (gdouble)layoutHeight / PANGO_SCALE;
            textWidth = (gdouble)layoutWidth / PANGO_SCALE;

            if (textWidth > maxWidthTime)
                maxWidthTime = textWidth;
            g_free(name);
            g_free(timeStr);
        } while(balanceView->GetNext(&name,&timeStr));
    }

    if (textHeight) {
        linesPerPage = (glong)(height / textHeight);
        gint pages = (gint)(totalCount / (linesPerPage?linesPerPage:totalCount));
        if (pages * linesPerPage < totalCount)
            ++pages;
        if (pages <= 0)
            pages = 1;
        gtk_print_operation_set_n_pages(operation, pages);
    } else
        gtk_print_operation_set_n_pages(operation, 1);

    g_object_unref (layout);
}


extern "C" void Report::DrawBalancePage(GtkPrintOperation *operation,GtkPrintContext *context, gint page_nr, gpointer user_data)
{
    Report::GetReport()->PrintBalancePage(operation, context, page_nr, user_data);
}

extern "C" void Report::BeginBalancePage(GtkPrintOperation *operation,GtkPrintContext *context, gpointer user_data)
{
    Report::GetReport()->PrintBalanceBegin(operation, context, user_data);
}

static GtkPrintSettings *settings = NULL;

void Report::Print()
{
    if (!summaryView && !detailView && !taskProgressView)
        return;
    maxWidth = 0;
    maxWidthDate = 0;
    maxWidthTime = 0;
    maxWidthPct = 0;
    maxWidthUsed = 0;

    /* Start printing. */
    GtkPrintOperation *op;
    GtkPrintOperationResult res;
    op = gtk_print_operation_new ();
    if (settings != NULL)
        gtk_print_operation_set_print_settings (op, settings);
    gtk_print_operation_set_n_pages (op, 1);
    gtk_print_operation_set_unit (op, GTK_UNIT_MM);
    if (summaryView) {
        g_signal_connect (op, "draw_page", G_CALLBACK (DrawPage), NULL);
        g_signal_connect (op, "begin_print", G_CALLBACK (BeginPage), NULL);
    } else if (detailView) {
        g_signal_connect (op, "draw_page", G_CALLBACK (DrawDetailPage), NULL);
        g_signal_connect (op, "begin_print", G_CALLBACK (BeginDetailPage), NULL);
    } else {
        g_signal_connect (op, "draw_page", G_CALLBACK (DrawTaskPage), NULL);
        g_signal_connect (op, "begin_print", G_CALLBACK (BeginTaskPage), NULL);
    }
    res = gtk_print_operation_run (op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL, NULL);
    if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
        if (settings != NULL)
            g_object_unref(settings);
        settings = (GtkPrintSettings*)g_object_ref(gtk_print_operation_get_print_settings(op));
    }

}





